package org.myhibernate.core.method;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

import org.myhibernate.cache.CacheContainer;
import org.myhibernate.cache.CacheContainers;
import org.myhibernate.cache.CacheItem;
import org.myhibernate.core.ISQueryAll;
import org.myhibernate.core.LanguageHandle;
import org.myhibernate.core.Mapping;
import org.myhibernate.core.Mappings;
import org.myhibernate.core.Seperators;
import org.myhibernate.db.DataHelper;

public class CacheQuery
{
	private  ResultSet resultSet=null;
	private Class cls=null;
	private  LanguageHandle handle=new LanguageHandle();
	private  boolean show=false;
	private DataHelper helper=null;  
	private CacheContainer cacheContainer=null;
	public CacheQuery(Class cls) 
	{ 
		this.cls = cls;
		this.show=Mappings.sqlShow;
		this.cacheContainer=CacheContainers.getCache(cls);
	}
	public CacheQuery(Connection connection, Class cls) 
	{
		this.cls = cls;
		this.show=Mappings.sqlShow;
		this.cacheContainer=CacheContainers.getCache(cls);
	}
	public CacheQuery(Class cls, DataHelper helper)
	{
		this.cls = cls;
		this.helper = helper;
		this.show=Mappings.sqlShow;
		this.cacheContainer=CacheContainers.getCache(cls);
	}
	public CacheQuery(Class cls,Connection connection, DataHelper helper)
	{
		this.cls = cls;
		this.helper = helper;
		if (connection!=null) {
			if (getHelper()==null) {
				this.helper=new DataHelper();
			}
			getHelper().setConnection(connection);
		}
		this.show=Mappings.sqlShow;
		this.cacheContainer=CacheContainers.getCache(cls);
	}
	public Class getCls() {
		return cls;
	}
	public void setCls(Class cls) {
		this.cls = cls;
	}
	
	public  Object getObject(Object id) throws Exception
	{
		Object object=cacheContainer.get(id);
		if (object==null)
		{
			object=queryOne(cls, id);
			if (object !=null) {
				cacheContainer.set(id, object);
			}
		}
		return object;
	}
	public  Object loadObject(Object id)throws Exception
	{
		Object object=null;
		object=queryOne(cls, id);
		if (object !=null) 
		{
			cacheContainer.set(id,object);
		}
		return object;
	}
	public  CacheItem getObjectItem(Object id)throws Exception
	{
		CacheItem item=cacheContainer.getItem(id);
		if (item==null)
		{
			Object object=queryOne(cls, id);
			if (object!=null) {
				item=new CacheItem(object);
				cacheContainer.setItem(id, item);
			}
		}
		return item;
	}
	private  Object queryOne(Class c,Object id) throws Exception
	{
		Object object=null;
		// query one
		Mapping mapping=Mappings.getMapping(c);
		String sql="";
		if (ISQueryAll.isQueryAll(cls))
		{
			sql="select * from "+mapping.getTable()+" where "+mapping.getId_Column()+"="+handle.handle(id);
		} else {
			sql="select "+mapping.getColumns()+" from "+mapping.getTable()+" where "+mapping.getId_Column()+"="+handle.handle(id);
		}
		
		boolean isShow=Mappings.sqlShow;
		List<String> columnList=mapping.getPropertyColList();
		try {
			if (show) {
				System.out.println(sql);
			}
			resultSet=getHelper().getStatement().executeQuery(sql);
			Object dataValue=null;
			if (resultSet.next())
			{
				object=c.newInstance();
				Field field =null;
				String fieldSimpleName="";
				Object tempDataValue=null;
				for (int i = 0; i < columnList.size(); i++)
				{
					try 
					{
						dataValue=resultSet.getObject(columnList.get(i));
						if (dataValue!=null)
						{
							tempDataValue=dataValue;
							//System.out.println("fileName="+mapping.getPropertyList().get(i));
							field = c.getDeclaredField(mapping.getPropertyList().get(i));
							fieldSimpleName=field.getType().getSimpleName().toLowerCase();
							//check database data to adapt to class data
							if (dataValue instanceof BigDecimal)
							{
								BigDecimal tempBigDecimal=(BigDecimal) dataValue;
								if ("float".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.floatValue();}
								if ("double".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.doubleValue();}
								if ("short".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.shortValue();}
								if ("int".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.intValue();}
								if ("integer".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.intValue();}
								if ("long".equals(fieldSimpleName)){tempDataValue=tempBigDecimal.longValue();}
								//bigdecimal
							}
							if (dataValue instanceof Integer)
							{
								Integer tempInteger=(Integer) dataValue;
								if ("short".equals(fieldSimpleName)){tempDataValue=tempInteger.shortValue();}
								if ("int".equals(fieldSimpleName)){tempDataValue=tempInteger.intValue();}
								if ("integer".equals(fieldSimpleName)){tempDataValue=tempInteger;}
								if ("long".equals(fieldSimpleName)){tempDataValue=tempInteger.longValue();}
							}
							//check class data for list
							if (("list".equals(fieldSimpleName))||("arraylist".equals(fieldSimpleName))) 
							{
								String listStrings=dataValue+"";
								ArrayList<String> tempList=new ArrayList<String>();
								tempDataValue=tempList;
								String[] ss=listStrings.split(Seperators.SEP1);
								String temp="";
								for (int j = 0; j < ss.length; j++) 
								{
									temp=ss[j];
									if ((temp!=null)&&(temp.trim().length()>0))
									{
										tempList.add(temp);
									}
								}
							}
							if (("linkedlist".equals(fieldSimpleName))) 
							{
								String listStrings=dataValue+"";
								LinkedList<String> tempList=new LinkedList<String>();
								tempDataValue=tempList;
								String[] ss=listStrings.split(Seperators.SEP1);
								String temp="";
								for (int j = 0; j < ss.length; j++) 
								{
									temp=ss[j];
									if ((temp!=null)&&(temp.trim().length()>0))
									{
										tempList.add(temp);
									}
								}
							}
							//check class data for map
							if (("map".equals(fieldSimpleName))||("hashmap".equals(fieldSimpleName))) 
							{
								String listStrings=dataValue+"";
								HashMap<String,String> tempMap=new HashMap<String,String>();
								tempDataValue=tempMap;
								String[] ss=listStrings.split(Seperators.SEP1);
								String temp="";
								for (int j = 0; j < ss.length; j++) 
								{
									temp=ss[j];
									if ((temp!=null)&&(temp.trim().length()>0)&&(temp.split("=").length>=2))
									{
										tempMap.put(temp.split("=")[0], temp.substring(temp.indexOf("=")+1));
									}
								}
							}
							if (("treemap".equals(fieldSimpleName))) 
							{
								String listStrings=dataValue+"";
								TreeMap<String,String> tempMap=new TreeMap<String,String>();
								tempDataValue=tempMap;
								String[] ss=listStrings.split(Seperators.SEP1);
								String temp="";
								for (int j = 0; j < ss.length; j++) 
								{
									temp=ss[j];
									if ((temp!=null)&&(temp.trim().length()>0)&&(temp.split("=").length>=2))
									{
										tempMap.put(temp.split("=")[0], temp.substring(temp.indexOf("=")+1));
									}
								}
							}
							
							Method method = c.getDeclaredMethod(mapping.getPropertySetList().get(i), field.getType());
							method.invoke(object, tempDataValue);
							
						}
						
					}
					catch (Exception e)
					{
						System.out.println("Exception for : "+columnList.get(i));
						System.out.println("Class field type:"+field.getType().getName());
						System.out.println("DataBase column type:"+resultSet.getObject(columnList.get(i)).getClass().getName());
						e.printStackTrace();
						throw new RuntimeException(e.toString());
					}
				}//endfor
			}//endif
		} catch (Exception e) 
		{
			e.printStackTrace();
			throw new RuntimeException(e.toString());
		}
		return object;
	}
	public boolean executeSql(String sql) throws Exception
	{
		ResultSet resultSet=null;
		try {
			if (show) {
				System.out.println(sql);
			}
			getHelper().getStatement().execute(sql);
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e.toString());
		}
	}
	public ResultSet executeQuerySql(String sql) throws Exception
	{
		ResultSet resultSet=null;
		try {
			if (show) {
				System.out.println(sql);
			}
			resultSet=getHelper().getStatement().executeQuery(sql);
			return resultSet;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e.toString());
		}
	}
	public DataHelper getHelper() {
		return helper;
	}
	public void close()
	{
	}
}
